<?php


namespace ke\graphql;


use GraphQL\Error\ClientAware;
use GraphQL\Error\DebugFlag;
use GraphQL\Error\Error;
use GraphQL\Error\FormattedError;
use GraphQL\Language\SourceLocation;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Schema;
use GraphQL\Utils\Utils;
use think\Container;
use think\facade\App;
use think\Request;

class GraphQl
{
    /**
     * @var Request
     */
    private $request;

    private $schema;

    public function __construct($class)
    {
        $service = new $class;
        $app = Container::get('app');
        $this->request = $app->request;

        $this->schema = new Schema([
            'query'=>new ObjectType([
                'name'=>'Query',
                'fields'=>$service->query(),
            ]),
            'mutation'=>new ObjectType([
                'name'=>'Mutation',
                'fields'=>$service->mutations(),
            ]),
        ]);
    }


    public static function build($class)
    {
        return new static($class);
    }


    public function send(array $rootValue = [], array $context = [])
    {
        $result = \GraphQL\GraphQL::executeQuery(
            $this->schema,
            $this->request->post('query'),
            $rootValue,
            $context
        );

//        $result->setErrorFormatter(function (Error $exception) {
//            // FormattedError::createFromException($error);
//
//            $internalErrorMessage = 'Internal server error';
//
//            if ($exception instanceof ClientAware) {
//                $formattedError = [
//                    'message'  => $exception->isClientSafe() ? $exception->getMessage() : $internalErrorMessage,
//                    'extensions' => [
//                        'category' => $exception->getCategory(),
//                    ],
//                ];
//            } else {
//                $formattedError = [
//                    'message'  => $internalErrorMessage,
//                    'extensions' => [
//                        'category' => Error::CATEGORY_INTERNAL,
//                    ],
//                ];
//            }
//
//            if ($exception instanceof Error) {
//                $locations = Utils::map(
//                    $exception->getLocations(),
//                    static function (SourceLocation $loc) : array {
//                        return $loc->toSerializableArray();
//                    }
//                );
//                if (count($locations) > 0) {
//                    $formattedError['locations'] = $locations;
//                }
//
//                if (count($exception->path ?? []) > 0) {
//                    $formattedError['path'] = $exception->path;
//                }
//                if (count($exception->getExtensions() ?? []) > 0) {
//                    $formattedError['extensions'] = $exception->getExtensions() + $formattedError['extensions'];
//                }
//            }
//
//            return $formattedError;
//        });
//
//        $result->setErrorsHandler(function (array $errors, callable $formatter) {
//            file_put_contents(App::getRuntimePath() . 'error.json', json_encode($errors, JSON_UNESCAPED_UNICODE));
//            return array_map($formatter, $errors);
//        });

        $debug = null;
        if (App::isDebug()) {
            $debug = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE;
        }

        return json($result->toArray($debug));
    }

}
